#include <cstdio>
#include <cstddef>



#include "transferdaemon.h"
#include "timestamp.h"

void* ansThread(void* _tran){
    TransferDaemon* tran = (TransferDaemon*)_tran;
    tran->answer();
    return (void*) 0;
}


TransferDaemon::TransferDaemon()
{
    this->m_sock = -1;
    this->m_working = false;
}

TransferDaemon::~TransferDaemon(){
    this->m_working = false;
    if(this->m_sock != -1){
        close(this->m_sock);
        pthread_cancel(this->m_ans_thread);
    }

    printf("transfer closed\t");
    TimeStamp::now()->print();
}

void TransferDaemon::startAnswer(){
    if (this->establishSocket() > 0){
        this->m_working = true;
        pthread_create(&this->m_ans_thread, NULL, &ansThread, (void*)this);
    }

}

int TransferDaemon::establishSocket(int port){
    struct sockaddr_in self_addr;
    int _sock = -1;
    int _port = port - 1;
    if ((_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("Socket");
        return -1;
    }
    do{
        self_addr.sin_family = AF_INET;
        _port += 1;
        self_addr.sin_port = htons(_port);
        self_addr.sin_addr.s_addr = INADDR_ANY;
        bzero(&(self_addr.sin_zero), 8);
    }while (bind(_sock, (struct sockaddr *) &self_addr, sizeof(struct sockaddr))
            == -1);

    this->m_port = _port;
    this->m_sock = _sock;
    printf("Socket established on port %d\n", this->m_port);
    return _port;
}

void TransferDaemon::answer(){
    while(this->m_working){
        struct sockaddr_in addr;
        socklen_t addr_len = sizeof(addr);
        int packet_length;
        normal_request_t request;
        packet_length = recvfrom(this->m_sock, &request, sizeof(request), 0, (struct sockaddr*)&addr, &addr_len);
        if(packet_length == sizeof(normal_request_t)){
            dealWithRequest(request, addr, addr_len);
        }
    }
}
void TransferDaemon::dealWithRequest(normal_request_t request, sockaddr_in addr, socklen_t addr_len){
//    printf("got request\t");
//    TimeStamp::now()->print();
    (*this->m_request_handler)(request, addr, addr_len);
}

void TransferDaemon::sendData(void *data, int size, sockaddr_in addr, socklen_t addr_len){
    int sent;
    sent = sendto(this->m_sock, data, size, 0, (struct sockaddr*)&addr, addr_len);
    if(sent != size){
        fprintf(stderr, "Error occurred in sendData!\n");
    }
}
